package prj9.spotsample;

import com.sun.spot.io.j2me.radiogram.RadiogramConnection;
import com.sun.spot.peripheral.Spot;
import com.sun.spot.resources.Resources;
import com.sun.spot.resources.transducers.ILed;
import com.sun.spot.resources.transducers.ISwitch;
import com.sun.spot.resources.transducers.ISwitchListener;
import com.sun.spot.resources.transducers.ITriColorLED;
import com.sun.spot.resources.transducers.ITriColorLEDArray;
import com.sun.spot.resources.transducers.LEDColor;
import com.sun.spot.resources.transducers.SwitchEvent;
import com.sun.spot.util.Utils;
import java.io.IOException;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;

/**
 *
 */
public class RelayNode {

    public static final String BROADCAST_ADDR = "radiogram://broadcast:110";
    public static final String ANYLISTEN_ADDR = "radiogram://:110";
    public static final int TRANSFER_QUEUE_SIZE = 1;
    public static final int TRANSFER_INTERVAL = 1000;
    Vector relayQueue;
    boolean cancelInvoked = false;
    Sender sender;
    Receiver receiver;
    int mode; // 0: Relay, 1: Sender, 2: Receiver
    int value;
    int seqNumber;
    private ITriColorLEDArray leds = (ITriColorLEDArray) Resources.lookup(ITriColorLEDArray.class);

    public RelayNode() throws IOException {
        System.out.println("RelayNode started.");
        Spot.getInstance().getRadioPolicyManager().setOutputPower(-31);
        this.cancelInvoked = false;
        this.relayQueue = new Vector();
        this.sender = new Sender();
        this.receiver = new Receiver();
        this.mode = 0;
        this.value = 0;


        ISwitch sw1 = (ISwitch) Resources.lookup(ISwitch.class, "SW1");
        sw1.addISwitchListener(new ISwitchListener() {
            public void switchPressed(SwitchEvent evt) {
            }

            public void switchReleased(SwitchEvent evt) {
                value = (value % 7) + 1;
                seqNumber++;
                if (mode == 1) {
                    relayQueue.addElement(new Integer(value));
                    updateLed(value);
                }
            }
        });
        ISwitch sw2 = (ISwitch) Resources.lookup(ISwitch.class, "SW2");
        sw2.addISwitchListener(new ISwitchListener() {
            int num = 1;

            public void switchPressed(SwitchEvent evt) {
            }

            public void switchReleased(SwitchEvent evt) {
                mode = (mode + 1) % 3;
                ITriColorLED led = leds.getLED(0);
                relayQueue.removeAllElements();
                switch (mode) {
                    case 0:
                        System.out.println("RELAY MODE");
                        led.setOff();
                        break;
                    case 1:
                        System.out.println("SENDER MODE");
                        led.setOn();
                        led.setColor(LEDColor.RED);
                        break;
                    case 2:
                        System.out.println("LISTENER MODE");
                        led.setOn();
                        led.setColor(LEDColor.BLUE);
                        break;
                    default:
                        break;
                }
            }
        });
    }

    private void updateLed(int value) {
        for (int i = 1; i < 8; i++) {
            ITriColorLED led = leds.getLED(i);
            if (i == value) {
                led.setOn();
                led.setColor(LEDColor.GREEN);
            } else {
                led.setOff();
            }
        }
    }

    public void work() {
        this.sender.start();
        this.receiver.start();
    }

    void stop() {
        cancelInvoked = true;
    }

    class Sender extends Thread {

        int msgPtr;
        RadiogramConnection conn;
        Datagram buffer;

        Sender() throws IOException {

            conn = (RadiogramConnection) Connector.open(BROADCAST_ADDR);
            buffer = conn.newDatagram(conn.getMaximumLength());
        }

        public void run() {
            System.out.println("Start sending...");
            while (!cancelInvoked) {
                while (relayQueue.size() > TRANSFER_QUEUE_SIZE) {
                    relayQueue.removeElementAt(0);
                }
                if (relayQueue.size() == 0) {
                    Utils.sleep(1000);
                    continue;
                } else {
                    msgPtr = (relayQueue.size() == 1)
                            ? 0
                            : ((msgPtr + 1) % (relayQueue.size() - 1));
                    try {
                        Integer msg = (Integer) relayQueue.elementAt(msgPtr);
                        send(msg.intValue());
                    } catch (IOException ex) {
                        System.out.println(msgPtr);
                        System.out.print("Exception[RelayNode.Sender]: ");
                        System.out.println(ex.getMessage());
                    }
                    Utils.sleep(TRANSFER_INTERVAL);
                }
            }
        }

        void send(int msg) throws IOException {
            System.out.println("Sending:" + msg);
            buffer.reset();
            buffer.writeInt(seqNumber);
            buffer.writeInt(msg);
            conn.send(buffer);
        }
    }

    class Receiver extends Thread {

        int lastSeqNumber;
        RadiogramConnection conn;
        Datagram buffer;

        public Receiver() throws IOException {
            conn = (RadiogramConnection) Connector.open(ANYLISTEN_ADDR);
            buffer = conn.newDatagram(conn.getMaximumLength());
            lastSeqNumber = 0;
        }

        public void run() {
            System.out.println("Listening...");
            while (!cancelInvoked) {
                if (conn.packetsAvailable()) {
                    try {
                        Integer msg = recv();
                        if (msg != null) {
                            if (mode == 0) {
                                relayQueue.addElement(msg);
                            }
                        }
                    } catch (IOException e) {
                        System.out.print("Exception[RelayNode.Receiver]: ");
                        System.out.println(e.getMessage());
                    }

                } else {
                    Utils.sleep(100);
                }
            }
        }

        Integer recv() throws IOException {
            buffer.reset();
            conn.receive(buffer);
            int sequene_num = buffer.readInt();
            if (lastSeqNumber > sequene_num) {
                return null;
            }
            int msg = buffer.readInt();
            System.out.println("Received: " + msg);
            if (msg < 8 && msg > 0) {
                updateLed(msg);
            } else {
                System.out.println("Invalid value!!" + msg);
            }
            return new Integer(msg);
        }
    }
}
